<?php

// Namespace

namespace Loop;


// Dependencies

require_once(PATH_LOOP . 'Model/CJob.php');


/**
 * CJobFactory 
 *
 * @package		Loop
 * @category	
 */

class CJobFactory
{
	/**
	 *
	 */

	public function api_listEligiblesJobs()
	{
		// Call the function

		$eligiblesJobs = $this->listEligiblesJobs();


		// Prepare variables

		$result  = $this->getCommand($eligiblesJobs);

		
		return $result;
	}


	/**
	 *
	 */

	public function api_runEligiblesJobs()
	{
		$this->runEligiblesJobs();
	}


	/**
	 *
	 */

	public function listEligiblesJobs()
	{
		// Define variables

		$eligiblesJobs = array();


		// Define objects

		$jobObject = new CJob();


		// Find the job

		$rawJobObjects = $jobObject->find
		(
			array
			(
				'conditions' => array
				(
					'timeOfRelease' => array(EQUAL, IS_NOT_NULL)
				)	
			)
		);


		// For each job found

		foreach ($rawJobObjects as $rawJobObject) 
		{
			// Load the raw

			$jobObject->loadFromRawObject($rawJobObject);


			// Is the job repeatable ?

			if ($jobObject->getIsRepeatable() == true)
			{

				// Get properties

				$daysOfWeek = $jobObject->getDaysOfWeek();
				$days = $jobObject->getDays();
				$hours = $jobObject->getHours();
				$minutes = $jobObject->getMinutes();
				$months = $jobObject->getMonths();

				$currentMonth = date('m');
				$currentDay = date('d');
				$currentMinute = date('i');
				$currentHour = date('H');

				
				// Test if the data for days are coherent

				if 
				(
					is_null($daysOfWeek) === false &&
					is_null($days) === false
				)
				{
					e(EXCEPTION_API_ARGUMENT_NOT_VALID);
				}


				//  Is there days of week ?

				if (is_null($daysOfWeek) === false)
				{
					// Is this a day of execution?

					if (in_array(date('l'), $daysOfWeek) === false)
					{
						// It's not the day

						continue;
					}	
				}
				else
				{
					// Is this a day of execution?
					
					$continue = $this->matchDate($currentDay, $days);

					if ($continue === false)
					{
						continue;
					}
				}


				// Is this a month of execution?

				$continue = $this->matchDate($currentMonth, $months);
				
				if ($continue === false)
				{
					continue;
				}			


				// Is this a minute of execution?

				$continue = $this->matchDate($currentMinute, $minutes);
				
				if ($continue === false)
				{
					continue;
				}			


				// Is this an hour of execution?

				$continue = $this->matchDate($currentHour, $hours);
				
				if ($continue === false)
				{
					continue;
				}
			}
			

			// Is the quota reached ?

			$continue = false;

			$apiQuota = $this->getQuota($jobObject->getApiName(), $jobObject->getClassName(), $jobObject->getExtensionId());


			if (is_null($apiQuota) === false)
			{
				$continue = $apiQuota->isQuotaExceeded();
			}	


			if ($continue === true)
			{
				continue;
			}			
				

			$eligiblesJobs[] = $rawJobObject;	

		}

		
		return $eligiblesJobs;
	}


	/**
	 *
	 */

	public function runEligiblesJobs()
	{
		// Dependencies

		require_once(PATH_LOOP . 'Model/CJobInstance.php');


		// Define objects

		$job = new CJob();


		// Get the eligibles jobs

		$eligiblesJobs = $this->listEligiblesJobs();


		// For each job found

		foreach($eligiblesJobs as $rawJobObject)
		{
			// Load the job

			$job->loadFromRawObject($rawJobObject);


			// Create the object

			$instance = new CJobInstance();


			// Set the properties

			$instance->setStatus('scheduled');
			$instance->setJobId($job->getId());
			$instance->setTimeOfStart(time());

			$instance->save();


			try
			{
				// Run the job

				$result = $job->run();
			}
			catch(\Exception $e)
			{
				$result['exceptions'] = $e;
			}

			if (isset($result['exceptions']) === true)
			{
				$instance->setStatus('failed');

				$trace = $result['exceptions'];
			}
			else
			{
				$instance->setStatus('completed');

				$trace = json_encode($result['result']);
			}


			// Set the properties for the result

			$instance->setTrace($trace);
			$instance->setTimeOfClosure(time());

			$instance->save();
		}
	}


	/**
	 *
	 */

	private function getCommand($eligiblesJobs)
	{
		// Get variables

		$universe = fv('universe');
		$env = fv('env');


		// Prepare variables

		$argumentEnv = '';
		$argumentUniverse = '';
		$ids = array();
		$references = array();


		// Is there a universe ?

		if (isset($universe) === true)
		{
			$argumentUniverse = '--universe="'. $universe .'"';
		}
		

		// Is there an environment ?	

		if (isset($env) === true)
		{
			$argumentEnv = ' --env="'. $env .'"';
		}


		// Define objects

		$job = new CJob();


		// For each job to execute

		foreach($eligiblesJobs as $rawJobObject)
		{
			// Load the job

			$job->loadFromRawObject($rawJobObject);


			$ids[] = $job->getId();
			$references[] = $job->getReference();
		}

		$command = 'php index.php ' . $argumentUniverse . $argumentEnv . ' --api="['. EXTENSION_LOOP . ']/JobFactory.runEligiblesJobs" --ids="' . json_encode($ids) . '" --references="' . json_encode($references) . '"';


		return $command;
	}


	/**
	 *
	 */

	public function getQuota($apiName, $className, $extensionId)
	{
		// Dependencies	

		require_once (PATH_LOOP . 'Model/CApiQuota.php');
		

		$apiQuota = new CApiQuota();


		$rawApiQuotas = $apiQuota->find
		(
			array
			(
				'conditions' => array
				(
					'apiName' => array(EQUAL, $apiName),
					'className' => array(EQUAL, $className),
					'extensionId' => array(EQUAL, $extensionId)
				)
			)
		);


		if (empty($rawApiQuotas) ===  true)
		{
			return null;
		}

		
		$rawApiQuota = array_shift($rawApiQuotas);


		$apiQuota->loadFromRawObject($rawApiQuota);


		return $apiQuota;
	}


	/**
	 *
	 */

	private function matchDate($current, $data)
	{
		preg_match('/^\*$/', $data, $matches);

		
		if (count($matches) == 0)
		{
			preg_match('/^([0-9]+)$/', $data, $matches);

			if (count($matches) == 0)
			{
				preg_match('/^([0-9]+)\-([0-9]+)$/', $data, $matches);

				if (count($matches) == 0)
				{
					preg_match('/^([0-9]+)(,([0-9]+))*$/', $data, $matches);

					if (count($matches) == 0)
					{
						e(EXCEPTION_API_ARGUMENT_NOT_VALID);
					}


					// Case  like 1,3

					$executions = explode(',', $data);

					if (in_array($current, $executions) === false)
					{
						return false;
					}
					else	
					{
						return true;
					}					
				}


				// Case like 1-2

				if
				(
					$current < $matches[1] ||
					$current > $matches[2]
				)
				{
					return false;
				}
				else	
				{
					return true;
				}				

			}


			// Case like 17

			if ($current != $matches[1])
			{
				return false;
			}
			else	
			{
				return true;
			}			
		}
		else	
		{
			return true;
		}
	}

}
?>